package cm.util;


import cm.dto.XxlJobInfoDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 解析XXL-JOB的CRON表达式，计算每天的执行时间
 */
@Slf4j
public class XxlJobParser {
    /**
     * 分析任务的CRON表达式，计算每天的执行时间
     *
     * @param jobInfoList
     * @return
     */
    public static List<XxlJobInfoDTO> analyzeJobList(List<XxlJobInfoDTO> jobInfoList) {
        List<XxlJobInfoDTO> analyzeJobList = new ArrayList<>();
        Map<Integer, XxlJobInfoDTO> jobInfoMap = ConvertTools.toMap(XxlJobInfoDTO::getId, jobInfoList);
        Map<Integer, List<String>> analyzeJobMap = analyzeJobMap(jobInfoList);

        for (Map.Entry<Integer, List<String>> entry : analyzeJobMap.entrySet()) {
            Integer jobId = entry.getKey();
            List<String> executionTimes = entry.getValue();
            if (jobInfoMap.containsKey(jobId)) {
                XxlJobInfoDTO jobInfoDTO = jobInfoMap.get(jobId);
                for (String executionTime : executionTimes) {
                    XxlJobInfoDTO newJogInfoDTO = new XxlJobInfoDTO();
                    BeanUtils.copyProperties(jobInfoDTO, newJogInfoDTO);
                    newJogInfoDTO.setExecuteTime(executionTime);
                    analyzeJobList.add(newJogInfoDTO);
                }
            }
        }

        Collections.sort(analyzeJobList);
        return analyzeJobList;
    }

    /**
     * 分析任务的CRON表达式，计算每天的执行时间
     *
     * @param jobInfoList
     * @return
     */
    public static Map<Integer, List<String>> analyzeJobMap(List<XxlJobInfoDTO> jobInfoList) {
        Map<Integer, List<String>> jobMap = new HashMap<>();
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");

        for (int i = 0; i < jobInfoList.size(); i++) {
            XxlJobInfoDTO xxlJobInfoDTO = jobInfoList.get(i);
            // 只处理CRON类型的任务
            if (!"CRON".equals(xxlJobInfoDTO.getScheduleType()) || xxlJobInfoDTO.getScheduleConf() == null) {
                continue;
            }

            List<String> executionTimes = new ArrayList<>();
            String cronExpression = xxlJobInfoDTO.getScheduleConf().trim();

            try {
                // 解析CRON表达式
                String[] parts = cronExpression.split("\\s+");
                if (parts.length < 6) {
                    continue; // 无效的CRON表达式
                }

                String seconds = parts[0];    // 秒
                String minutes = parts[1];    // 分
                String hours = parts[2];     // 时
                String dayOfMonth = parts[3]; // 日
                String month = parts[4];      // 月
                String dayOfWeek = parts[5];  // 周

                // 检查是否是每天执行的任务（日和周都是*）
                if (!"*".equals(dayOfMonth) || !"?".equals(dayOfWeek)) {
                    continue; // 不是每天执行的任务
                }

                // 处理小时部分
                if (hours.contains(",")) {
                    // 多个小时点执行
                    for (String hour : hours.split(",")) {
                        if (hour.contains("/")) {
                            // 处理间隔小时，如 8/2 表示8点开始，每2小时一次
                            String[] intervalParts = hour.split("/");
                            int startHour = Integer.parseInt(intervalParts[0]);
                            int interval = Integer.parseInt(intervalParts[1]);

                            for (int h = startHour; h < 24; h += interval) {
                                calculateExecutionTime(executionTimes, h, minutes, seconds, timeFormatter);
                            }
                        } else {
                            calculateExecutionTime(executionTimes, Integer.parseInt(hour), minutes, seconds, timeFormatter);
                        }
                    }
                } else if (hours.contains("/")) {
                    // 处理间隔小时，如 */2 表示每2小时一次
                    String[] intervalParts = hours.split("/");
                    int interval = Integer.parseInt(intervalParts[1]);

                    for (int h = 0; h < 24; h += interval) {
                        calculateExecutionTime(executionTimes, h, minutes, seconds, timeFormatter);
                    }
                } else if (hours.contains("-")) {
                    // 处理间隔小时，如 */2 表示每2小时一次
                    String[] intervalParts = hours.split("-");
                    for (int hour = Integer.valueOf(intervalParts[0]); hour <= Integer.valueOf(intervalParts[1]); hour++) {
                        calculateExecutionTime(executionTimes, hour, minutes, seconds, timeFormatter);
                    }
                } else if ("*".equals(hours)) {
                    // 每小时执行
                    for (int h = 0; h < 24; h++) {
                        calculateExecutionTime(executionTimes, h, minutes, seconds, timeFormatter);
                    }
                } else {
                    // 单次执行
                    calculateExecutionTime(executionTimes, Integer.parseInt(hours), minutes, seconds, timeFormatter);
                }

                if (!executionTimes.isEmpty()) {
                    jobMap.put(xxlJobInfoDTO.getId(), executionTimes);
                }
            } catch (Exception e) {
                log.error("Error parsing cron expression for job {}: {}", xxlJobInfoDTO.getId(), cronExpression, e);
            }
        }

        return jobMap;
    }

    /**
     * 计算具体的执行时间
     *
     * @param hour
     * @param minutes
     * @param seconds
     * @param formatter
     * @return
     */
    private static void calculateExecutionTime(List<String> executionTimes, int hour, String minutes, String seconds,
                                               DateTimeFormatter formatter) {
        if (minutes.contains("/")) {
            String[] intervalParts = minutes.split("/");
            int interval = Integer.parseInt(intervalParts[1]);
            for (int m = 0; m < 60; m += interval) {
                calculateExecutionTime(executionTimes, hour, m, seconds, formatter);
            }
        } else if (minutes.contains(",")) {
            String[] items = minutes.split(",");
            for (String item : items) {
                calculateExecutionTime(executionTimes, hour, Integer.valueOf(item), seconds, formatter);
            }
        } else {
            int minute = "*".equals(minutes) ? 0 : Integer.parseInt(minutes);
            calculateExecutionTime(executionTimes, hour, minute, seconds, formatter);
        }
    }

    private static void calculateExecutionTime(List<String> executionTimes, int hour, Integer minute, String seconds,
                                               DateTimeFormatter formatter) {
        try {
            int second = "*".equals(seconds) ? 0 : Integer.parseInt(seconds);

            // 确保时间在合法范围内
            hour = Math.min(23, Math.max(0, hour));
            minute = Math.min(59, Math.max(0, minute));
            second = Math.min(59, Math.max(0, second));

            LocalTime time = LocalTime.of(hour, minute, second);
            executionTimes.add(time.format(formatter));
        } catch (NumberFormatException e) {
            executionTimes.add("Invalid time");
        }
    }

}
